#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>

#include "src/base64.h"
#include "src/sha_helper.h"

#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))

void test_base64() {
    static const std::string vstrIn[]  = {"", "f", "fo", "foo", "foob", "fooba", "foobar"};
    static const std::string vstrOut[] = {"",         "Zg==",     "Zm8=",    "Zm9v",
                                          "Zm9vYg==", "Zm9vYmE=", "Zm9vYmFy"};

    for (unsigned int i = 0; i < ARRAY_SIZE(vstrIn); i++) {
        std::string strEnc;
        Base64Encode(vstrIn[i], &strEnc);
        assert(strEnc == vstrOut[i]);
        std::string strDec;
        Base64Decode(strEnc, &strDec);
        assert(strDec == vstrIn[i]);
    }

    // Decoding strings with embedded NUL characters should fail
    std::string output;
    bool success = Base64Decode("invalid\0", &output);
    assert(!success);

    success = Base64Decode("nQB/pZw=", &output);
    assert(success);

    success = Base64Decode("nQB/pZw=\0invalid", &output);
    assert(success);

    success = Base64Decode("nQB/pZw=invalid\0", &output);
    assert(!success);
}

#define single_size 1048576L

void check_sha_alg(const std::string &file) {
    helper::SHA256 sha256;
    helper::SHA1 sha1;

    FILE *f = fopen(file.c_str(), "rb");
    fseek(f, 0, SEEK_END);

    long file_size = ftell(f);
    long read_size = 0;

    char *buff = new char[single_size];
    fseek(f, 0, SEEK_SET);

    while (read_size < file_size) {
        long need = std::min(single_size, file_size - read_size);
        long real = fread(buff, 1, need, f);
        if (real != need) {
            abort();
        }
        read_size += real;
        sha1.Write(buff, real);
        sha256.Write(buff, real);
    }

    delete[] buff;
    fclose(f);

    std::string str_sha1   = sha1.ReadableResult();
    std::string str_sha256 = sha256.ReadableResult();

    std::cout << "sha1:" << str_sha1 << ", size:" << str_sha1.size() << std::endl;
    std::cout << "sha256:" << str_sha256 << ", size:" << str_sha256.size() << std::endl;
}

int main() {
    test_base64();
    return 0;
}
